import { useContext, useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import type { TBody } from '@/types';
import {
  createFavourite,
  createFollow,
  postCancelFavourite,
  postCancelFollow,
  postCancelLike,
  postFavourite,
  postFollow,
  postLike,
  removeFavourite,
  removeFollow,
} from '@/services/api';
import useToast, { LoginReminderContent } from '@/hooks/useToast';
import useUser from '@/hooks/useUser';
import clipboard from 'clipboard';
import { scrollToBottom } from '@/lib/tool';
import { PostIdPageContext } from '@/contexts/post-id';
import { AppContext } from '@/contexts/app';

export default function ButtonAreaPostIdPage({
  id,
  name,
  like = false,
  likeNum = 0,
  follow = false,
  followNum = 0,
  favourite = false,
  favouriteNum = 0,
}: {
  id: number;
  name: string;
  like?: boolean;
  likeNum?: number;
  follow?: boolean;
  followNum?: number;
  favourite?: boolean;
  favouriteNum?: number;
}) {
  return (
    <div className="vstack my-5 gap-3 justify-content-around">
      <div className="hstack gap-4 justify-content-center">
        <CommentBtn />
        <LikeBtn id={id} like={like} likeNum={likeNum} />
        <FollowBtn id={id} follow={follow} followNum={followNum} />
      </div>
      <div className="hstack gap-4 justify-content-center">
        <ShareBtn name={name} />
        <FavouriteBtn
          id={id}
          favourite={favourite}
          favouriteNum={favouriteNum}
        />
      </div>
    </div>
  );
}

const CommentBtn = () => {
  const { translatedFields } = useContext(PostIdPageContext)!;

  function onClickComment() {
    scrollToBottom();
  }

  return (
    <button onClick={onClickComment} type="button" className="btn">
      <i className="bi bi-reply me-2"></i>
      {translatedFields.comment}
    </button>
  );
};

const LikeBtn = ({
  id,
  like = false,
  likeNum = 0,
}: {
  id: number;
  like?: boolean;
  likeNum?: number;
}) => {
  const {
    source: { path },
  } = useContext(PostIdPageContext)!;
  const { show } = useToast();
  const [isLike, setIsLike] = useState(like);
  const [likeCount, setLikeCount] = useState(likeNum);
  const { translatedFields } = useContext(PostIdPageContext)!;

  const likeMutation = useMutation(async (variables: TBody<void>) => {
    await postLike(variables);
  });
  const cancelLikeMutation = useMutation(async (variables: TBody<void>) => {
    await postCancelLike(variables);
  });

  async function onClickLike() {
    try {
      if (!path.user) {
        show({
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      let message;
      if (isLike) {
        await cancelLikeMutation.mutateAsync({ id });
        message = translatedFields.alreadyCancelled;
        setIsLike(false);
        setLikeCount(likeCount - 1);
      } else {
        await likeMutation.mutateAsync({ id });
        message = translatedFields.alreadyLiked;
        setIsLike(true);
        setLikeCount(likeCount + 1);
      }

      show({
        type: 'SUCCESS',
        message,
      });
    } catch (e) {
      if (isLike) {
        cancelLikeMutation.reset();
      } else {
        likeMutation.reset();
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <button
      disabled={likeMutation.isLoading || cancelLikeMutation.isLoading}
      onClick={onClickLike}
      type="button"
      className="btn position-relative"
    >
      {isLike ? (
        <span>
          {cancelLikeMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-hand-thumbs-up-fill me-2"></i>
          )}
          {translatedFields.alreadyLiked}
        </span>
      ) : (
        <span>
          {likeMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-hand-thumbs-up me-2"></i>
          )}
          {translatedFields.like}
        </span>
      )}

      {likeCount > 0 && (
        <span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-secondary bg-opacity-75">
          {likeCount > 99 ? '99+' : likeCount > 999 ? '999+' : likeCount}
          <span className="visually-hidden">{translatedFields.likeCount}</span>
        </span>
      )}
    </button>
  );
};

const FollowBtn = ({
  id,
  follow = false,
  followNum = 0,
}: {
  id: number;
  follow?: boolean;
  followNum?: number;
}) => {
  const { translatedFields } = useContext(PostIdPageContext)!;
  const appContext = useContext(AppContext);
  const metadata = appContext.metadata!;
  const userQuery = useUser(metadata);
  const { show } = useToast();
  const [isFollow, setIsFollow] = useState(follow);
  const [followCount, setFollowCount] = useState(followNum);

  const followMutation = useMutation(async (variables: TBody<void>) => {
    await postFollow(variables);
  });
  const cancelFollowMutation = useMutation(async (variables: TBody<void>) => {
    await postCancelFollow(variables);
  });
  const createFollowMutation = useMutation(async (variables: TBody<void>) => {
    await createFollow(variables);
  });
  const removeFollowMutation = useMutation(async (variables: TBody<void>) => {
    await removeFollow(variables);
  });

  async function onClickFollow() {
    try {
      if (!userQuery.data!.user) {
        show({
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      let message;

      if (isFollow) {
        await Promise.all([
          removeFollowMutation.mutateAsync({ id }),
          cancelFollowMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyCancelled;
        setIsFollow(false);
        setFollowCount(followCount - 1);
      } else {
        await Promise.all([
          createFollowMutation.mutateAsync({ id }),
          followMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyFollowed;
        setIsFollow(true);
        setFollowCount(followCount + 1);
      }

      show({
        type: 'SUCCESS',
        message,
      });
    } catch (e) {
      if (isFollow) {
        removeFollowMutation.reset();
        cancelFollowMutation.reset();
      } else {
        createFollowMutation.reset();
        followMutation.reset();
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <button
      disabled={
        createFollowMutation.isLoading ||
        followMutation.isLoading ||
        removeFollowMutation.isLoading ||
        cancelFollowMutation.isLoading
      }
      onClick={onClickFollow}
      type="button"
      className="btn position-relative"
    >
      {isFollow ? (
        <span>
          {removeFollowMutation.isLoading || cancelFollowMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-bell-fill me-2"></i>
          )}
          {translatedFields.alreadyFollowed}
        </span>
      ) : (
        <span>
          {createFollowMutation.isLoading || followMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-bell me-2"></i>
          )}
          {translatedFields.follow}
        </span>
      )}

      {followCount > 0 && (
        <span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-secondary bg-opacity-75">
          {followCount > 99 ? '99+' : followCount > 999 ? '999+' : followCount}
          <span className="visually-hidden">
            {translatedFields.followCount}
          </span>
        </span>
      )}
    </button>
  );
};

const ShareBtn = ({ name }: { name: string }) => {
  const { show } = useToast();
  const { translatedFields } = useContext(PostIdPageContext)!;

  function onClickShare() {
    clipboard.copy(`[${name}](${location.href})`);
    show({
      type: 'SUCCESS',
      message: translatedFields.copyCompleted,
    });
  }

  return (
    <button onClick={onClickShare} type="button" className="btn ">
      <span>
        <i className="bi bi-share me-2"></i>
        {translatedFields.share}
      </span>
    </button>
  );
};

const FavouriteBtn = ({
  id,
  favourite = false,
  favouriteNum = 0,
}: {
  id: number;
  favourite?: boolean;
  favouriteNum?: number;
}) => {
  const { translatedFields } = useContext(PostIdPageContext)!;
  const appContext = useContext(AppContext);
  const metadata = appContext.metadata!;
  const userQuery = useUser(metadata);
  const { show } = useToast();
  const [isFavourite, setIsFavourite] = useState(favourite);
  const [favoriteCount, setFavoriteCount] = useState(favouriteNum);

  const favouriteMutation = useMutation(async (variables: TBody<void>) => {
    await postFavourite(variables);
  });
  const cancelFavouriteMutation = useMutation(
    async (variables: TBody<void>) => {
      await postCancelFavourite(variables);
    },
  );
  const createFavouriteMutation = useMutation(
    async (variables: TBody<void>) => {
      await createFavourite(variables);
    },
  );
  const removeFavouriteMutation = useMutation(
    async (variables: TBody<void>) => {
      await removeFavourite(variables);
    },
  );

  async function onClickFavourite() {
    try {
      if (!userQuery.data!.user) {
        show({
          title: translatedFields.notLoggedInPrompt,
          content: <LoginReminderContent />,
        });
        return;
      }

      let message;

      if (isFavourite) {
        await Promise.all([
          removeFavouriteMutation.mutateAsync({ id }),
          cancelFavouriteMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyCancelled;
        setIsFavourite(false);
        setFavoriteCount(favoriteCount - 1);
      } else {
        await Promise.all([
          createFavouriteMutation.mutateAsync({ id }),
          favouriteMutation.mutateAsync({ id }),
        ]);
        message = translatedFields.alreadyBookmarked;
        setIsFavourite(true);
        setFavoriteCount(favoriteCount + 1);
      }

      show({
        type: 'SUCCESS',
        message,
      });
    } catch (e) {
      if (isFavourite) {
        removeFavouriteMutation.reset();
        cancelFavouriteMutation.reset();
      } else {
        createFavouriteMutation.reset();
        favouriteMutation.reset();
      }

      show({
        type: 'DANGER',
        message: e,
      });
    }
  }

  return (
    <button
      disabled={
        createFavouriteMutation.isLoading ||
        favouriteMutation.isLoading ||
        removeFavouriteMutation.isLoading ||
        cancelFavouriteMutation.isLoading
      }
      onClick={onClickFavourite}
      type="button"
      className="btn position-relative"
    >
      {isFavourite ? (
        <span>
          {removeFavouriteMutation.isLoading ||
          cancelFavouriteMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-star-fill me-2"></i>
          )}
          {translatedFields.alreadyBookmarked}
        </span>
      ) : (
        <span>
          {createFavouriteMutation.isLoading || favouriteMutation.isLoading ? (
            <span
              className="spinner-border spinner-border-sm me-2"
              role="status"
              aria-hidden="true"
            ></span>
          ) : (
            <i className="bi bi-star me-2"></i>
          )}
          {translatedFields.bookmark}
        </span>
      )}

      {favoriteCount > 0 && (
        <span className="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-secondary bg-opacity-75">
          {favoriteCount > 99
            ? '99+'
            : favoriteCount > 999
            ? '999+'
            : favoriteCount}
          <span className="visually-hidden">
            {translatedFields.bookmarkCount}
          </span>
        </span>
      )}
    </button>
  );
};
